<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>玉米病变识别系统</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        body {
            background: linear-gradient(135deg, #f5f7fa 0%, #e4efe9 100%);
            min-height: 100vh;
            padding: 20px;
            color: #333;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
        }

        header {
            text-align: center;
            padding: 30px 0;
            margin-bottom: 30px;
        }

        .logo {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 15px;
            margin-bottom: 15px;
        }

        .logo i {
            font-size: 2.5rem;
            color: #4CAF50;
        }

        h1 {
            font-size: 2.5rem;
            color: #2E7D32;
            text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
        }

        .subtitle {
            font-size: 1.2rem;
            color: #666;
            max-width: 700px;
            margin: 0 auto;
            line-height: 1.6;
        }

        .card {
            background: white;
            border-radius: 16px;
            box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08);
            padding: 30px;
            margin-bottom: 30px;
            transition: transform 0.3s ease, box-shadow 0.3s ease;
        }

        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 12px 40px rgba(0, 0, 0, 0.12);
        }

        .card-title {
            font-size: 1.5rem;
            margin-bottom: 20px;
            color: #2E7D32;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .upload-area {
            border: 2px dashed #81C784;
            border-radius: 12px;
            padding: 40px 20px;
            text-align: center;
            background-color: #F1F8E9;
            cursor: pointer;
            transition: all 0.3s ease;
        }

        .upload-area:hover {
            background-color: #E8F5E9;
            border-color: #4CAF50;
        }

        .upload-area i {
            font-size: 3rem;
            color: #81C784;
            margin-bottom: 15px;
        }

        .upload-text {
            font-size: 1.2rem;
            color: #555;
            margin-bottom: 15px;
        }

        .btn {
            background: linear-gradient(135deg, #4CAF50 0%, #2E7D32 100%);
            color: white;
            border: none;
            padding: 12px 30px;
            font-size: 1.1rem;
            border-radius: 50px;
            cursor: pointer;
            transition: all 0.3s ease;
            font-weight: 600;
            box-shadow: 0 4px 15px rgba(76, 175, 80, 0.3);
        }

        .btn:hover {
            transform: translateY(-3px);
            box-shadow: 0 6px 20px rgba(76, 175, 80, 0.4);
        }

        .btn:disabled {
            background: #BDBDBD;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }

        .image-preview {
            margin-top: 25px;
            text-align: center;
        }

        .preview-title {
            font-size: 1.2rem;
            margin-bottom: 15px;
            color: #555;
        }

        .preview-img {
            max-width: 100%;
            max-height: 300px;
            border-radius: 12px;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
        }

        .results-container {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 25px;
            margin-top: 20px;
        }

        .model-result {
            background: #F1F8E9;
            border-radius: 12px;
            padding: 20px;
            transition: transform 0.3s ease;
        }

        .model-result:hover {
            transform: translateY(-5px);
        }

        .model-header {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-bottom: 15px;
        }

        .model-name {
            font-size: 1.3rem;
            font-weight: 600;
            color: #2E7D32;
        }

        .prediction {
            font-size: 1.5rem;
            font-weight: bold;
            margin: 15px 0;
            color: #1B5E20;
        }

        .confidence {
            font-size: 1.1rem;
            margin-bottom: 15px;
            color: #555;
        }

        .progress-container {
            height: 12px;
            background: #E0E0E0;
            border-radius: 10px;
            margin: 20px 0;
            overflow: hidden;
        }

        .progress-bar {
            height: 100%;
            background: linear-gradient(90deg, #81C784 0%, #4CAF50 100%);
            border-radius: 10px;
            transition: width 0.5s ease;
        }

        .probabilities {
            margin-top: 20px;
        }

        .prob-item {
            display: flex;
            justify-content: space-between;
            padding: 8px 0;
            border-bottom: 1px solid #E0E0E0;
        }

        .prob-label {
            font-weight: 500;
        }

        .prob-value {
            color: #2E7D32;
            font-weight: 600;
        }

        .accuracy-table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
            border-radius: 12px;
            overflow: hidden;
        }

        .accuracy-table th {
            background: #2E7D32;
            color: white;
            padding: 15px;
            text-align: left;
        }

        .accuracy-table td {
            padding: 15px;
            border-bottom: 1px solid #E0E0E0;
        }

        .accuracy-table tr:nth-child(even) {
            background-color: #F1F8E9;
        }

        .accuracy-table tr:hover {
            background-color: #E8F5E9;
        }

        .accuracy-value {
            font-weight: bold;
            color: #2E7D32;
        }

        .best-accuracy {
            background-color: #C8E6C9 !important;
            font-weight: bold;
        }

        .loading {
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 30px;
        }

        .spinner {
            width: 50px;
            height: 50px;
            border: 5px solid rgba(76, 175, 80, 0.2);
            border-top: 5px solid #4CAF50;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        footer {
            text-align: center;
            padding: 30px 0;
            color: #666;
            font-size: 0.9rem;
        }

        @media (max-width: 768px) {
            .results-container {
                grid-template-columns: 1fr;
            }

            h1 {
                font-size: 2rem;
            }
        }
    </style>
</head>
<body>
<div id="app">
    <div class="container">
        <header>
            <div class="logo">
                <i class="fas fa-leaf"></i>
                <h1>玉米病变识别系统</h1>
            </div>
            <p class="subtitle">上传玉米叶片图片，系统将使用先进的视觉Transformer模型进行病变识别，并提供详细的诊断报告</p>
        </header>

        <main>
            <div class="card">
                <h2 class="card-title"><i class="fas fa-cloud-upload-alt"></i> 图片上传</h2>
                <div class="upload-area" @click="triggerFileInput" @dragover.prevent @drop.prevent="handleDrop">
                    <i class="fas fa-file-image"></i>
                    <p class="upload-text">点击或拖拽图片到此处上传</p>
                    <p style="color: #888; margin-bottom: 15px;">支持 JPG、PNG 格式，最大 5MB</p>
                    <button class="btn">选择图片</button>
                    <input type="file" ref="fileInput" @change="handleFileChange" accept="image/*" hidden>
                </div>

                <div class="image-preview" v-if="previewUrl">
                    <p class="preview-title">图片预览</p>
                    <img :src="previewUrl" alt="预览图" class="preview-img">
                </div>

                <div style="text-align: center; margin-top: 25px;">
                    <button class="btn" @click="analyzeImage" :disabled="!previewUrl || isLoading">
                        <span v-if="!isLoading">开始分析</span>
                        <span v-else>分析中...</span>
                    </button>
                </div>
            </div>

            <div class="card" v-if="resultsVisible">
                <h2 class="card-title"><i class="fas fa-chart-line"></i> 模型识别结果</h2>
                <div class="results-container">
                    <div class="model-result">
                        <div class="model-header">
                            <i class="fas fa-robot" style="color: #4CAF50;"></i>
                            <span class="model-name">T2T-ViT 模型</span>
                        </div>
                        <div v-if="results.t2tvit">
                            <div class="prediction">{{ results.t2tvit.prediction }}</div>
                            <div class="confidence">置信度: {{ (results.t2tvit.confidence * 100).toFixed(2) }}%</div>
                            <div class="progress-container">
                                <div class="progress-bar" :style="{ width: (results.t2tvit.confidence * 100) + '%' }"></div>
                            </div>
                            <div class="probabilities">
                                <div class="prob-item" v-for="(prob, disease) in results.t2tvit.probabilities" :key="disease">
                                    <span class="prob-label">{{ diseaseMap[disease] || disease }}</span>
                                    <span class="prob-value">{{ (prob * 100).toFixed(1) }}%</span>
                                </div>
                            </div>
                        </div>
                        <div v-else class="loading">
                            <div class="spinner"></div>
                        </div>
                    </div>

                    <div class="model-result">
                        <div class="model-header">
                            <i class="fas fa-robot" style="color: #FF9800;"></i>
                            <span class="model-name">ViT-Lite 模型</span>
                        </div>
                        <div v-if="results.vitlite">
                            <div class="prediction">{{ results.vitlite.prediction }}</div>
                            <div class="confidence">置信度: {{ (results.vitlite.confidence * 100).toFixed(2) }}%</div>
                            <div class="progress-container">
                                <div class="progress-bar" :style="{ width: (results.vitlite.confidence * 100) + '%' }"></div>
                            </div>
                            <div class="probabilities">
                                <div class="prob-item" v-for="(prob, disease) in results.vitlite.probabilities" :key="disease">
                                    <span class="prob-label">{{ diseaseMap[disease] || disease }}</span>
                                    <span class="prob-value">{{ (prob * 100).toFixed(1) }}%</span>
                                </div>
                            </div>
                        </div>
                        <div v-else class="loading">
                            <div class="spinner"></div>
                        </div>
                    </div>

                    <div class="model-result">
                        <div class="model-header">
                            <i class="fas fa-robot" style="color: #2196F3;"></i>
                            <span class="model-name">ViT 模型</span>
                        </div>
                        <div v-if="results.vit">
                            <div class="prediction">{{ results.vit.prediction }}</div>
                            <div class="confidence">置信度: {{ (results.vit.confidence * 100).toFixed(2) }}%</div>
                            <div class="progress-container">
                                <div class="progress-bar" :style="{ width: (results.vit.confidence * 100) + '%' }"></div>
                            </div>
                            <div class="probabilities">
                                <div class="prob-item" v-for="(prob, disease) in results.vit.probabilities" :key="disease">
                                    <span class="prob-label">{{ diseaseMap[disease] || disease }}</span>
                                    <span class="prob-value">{{ (prob * 100).toFixed(1) }}%</span>
                                </div>
                            </div>
                        </div>
                        <div v-else class="loading">
                            <div class="spinner"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="card">
                <h2 class="card-title"><i class="fas fa-table"></i> 模型精度对比</h2>
                <table class="accuracy-table">
                    <thead>
                    <tr>
                        <th>模型名称</th>
                        <th>参数量</th>
                        <th>推理速度 (ms)</th>
                        <th>准确率</th>
                        <th>F1 分数</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr :class="{ 'best-accuracy': model.accuracy === highestAccuracy }" v-for="model in modelComparison" :key="model.name">
                        <td>{{ model.name }}</td>
                        <td>{{ model.params }}</td>
                        <td>{{ model.speed }}</td>
                        <td><span class="accuracy-value">{{ model.accuracy }}%</span></td>
                        <td>{{ model.f1 }}</td>
                    </tr>
                    </tbody>
                </table>
            </div>
        </main>

        <footer>
            <p>玉米病变识别系统 &copy; 2023 | 农业科技创新应用</p>
        </footer>
    </div>
</div>

<script>
    const { createApp, ref, reactive, computed } = Vue;

    createApp({
        setup() {
            const fileInput = ref(null);
            const previewUrl = ref('');
            const imageFile = ref(null);
            const isLoading = ref(false);
            const resultsVisible = ref(false);

            // 疾病名称映射
            const diseaseMap = {
                blight: "玉米大斑病",
                common_rust: "玉米普通锈病",
                gray_spot: "玉米灰斑病",
                spray: "健康叶片"
            };

            // 模型结果数据
            const results = reactive({
                t2tvit: null,
                vitlite: null,
                vit: null
            });

            // 模型精度对比数据
            const modelComparison = [
                { name: "T2T-ViT", params: "21.5M", speed: "45", accuracy: "96.2", f1: "0.958" },
                { name: "ViT-Lite", params: "5.8M", speed: "28", accuracy: "94.5", f1: "0.938" },
                { name: "ViT", params: "86.6M", speed: "78", accuracy: "95.8", f1: "0.952" }
            ];

            // 计算最高准确率
            const highestAccuracy = computed(() => {
                return Math.max(...modelComparison.map(m => parseFloat(m.accuracy)));
            });

            // 触发文件选择
            const triggerFileInput = () => {
                fileInput.value.click();
            };

            // 处理文件选择
            const handleFileChange = (e) => {
                const file = e.target.files[0];
                if (file && file.type.match('image.*')) {
                    imageFile.value = file;
                    previewUrl.value = URL.createObjectURL(file);
                    resultsVisible.value = false;
                }
            };

            // 处理拖放
            const handleDrop = (e) => {
                e.preventDefault();
                const file = e.dataTransfer.files[0];
                if (file && file.type.match('image.*')) {
                    imageFile.value = file;
                    previewUrl.value = URL.createObjectURL(file);
                    resultsVisible.value = false;
                }
            };

            // 分析图片
            const analyzeImage = async () => {
                if (!imageFile.value) return;

                isLoading.value = true;
                resultsVisible.value = true;

                // 重置结果
                results.t2tvit = null;
                results.vitlite = null;
                results.vit = null;

                try {
                    // 模拟API请求 - 在实际应用中应替换为真实API调用
                    await new Promise(resolve => setTimeout(resolve, 1500));

                    // 模拟结果数据 - 在实际应用中应使用真实API响应
                    results.t2tvit = {
                        prediction: "玉米灰斑病",
                        confidence: 0.956,
                        probabilities: {
                            blight: 0.023,
                            common_rust: 0.012,
                            gray_spot: 0.956,
                            spray: 0.009
                        }
                    };

                    await new Promise(resolve => setTimeout(resolve, 1200));

                    results.vitlite = {
                        prediction: "玉米灰斑病",
                        confidence: 0.921,
                        probabilities: {
                            blight: 0.045,
                            common_rust: 0.022,
                            gray_spot: 0.921,
                            spray: 0.012
                        }
                    };

                    await new Promise(resolve => setTimeout(resolve, 1800));

                    results.vit = {
                        prediction: "玉米灰斑病",
                        confidence: 0.938,
                        probabilities: {
                            blight: 0.032,
                            common_rust: 0.018,
                            gray_spot: 0.938,
                            spray: 0.012
                        }
                    };

                } catch (error) {
                    console.error("分析失败:", error);
                    alert("图片分析失败，请重试");
                } finally {
                    isLoading.value = false;
                }

                // 实际API调用示例（需要后端实现）：
                /*
                const formData = new FormData();
                formData.append('file', imageFile.value);

                try {
                  // T2T-ViT 模型请求
                  const t2tResponse = await axios.post('/predict/t2tvit', formData, {
                    headers: { 'Content-Type': 'multipart/form-data' }
                  });
                  results.t2tvit = t2tResponse.data;

                  // ViT-Lite 模型请求
                  const vitliteResponse = await axios.post('/predict/vitlite', formData, {
                    headers: { 'Content-Type': 'multipart/form-data' }
                  });
                  results.vitlite = vitliteResponse.data;

                  // ViT 模型请求
                  const vitResponse = await axios.post('/predict/vit', formData, {
                    headers: { 'Content-Type': 'multipart/form-data' }
                  });
                  results.vit = vitResponse.data;
                } catch (error) {
                  console.error("API请求失败:", error);
                  alert("分析失败，请重试");
                } finally {
                  isLoading.value = false;
                }
                */
            };

            return {
                fileInput,
                previewUrl,
                isLoading,
                resultsVisible,
                results,
                diseaseMap,
                modelComparison,
                highestAccuracy,
                triggerFileInput,
                handleFileChange,
                handleDrop,
                analyzeImage
            };
        }
    }).mount('#app');
</script>
</body>
</html>